﻿using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using IndieStudio.BugsBang.Game;

///Developed By Indie Studio
///https://assetstore.unity.com/publishers/9268
///www.indiestd.com
///info@indiestd.com

namespace IndieStudio.BugsBang.Utility
{
	/// <summary>
	/// Data manager.
	/// (Manages saving(writing)/loading(reading) the data of the game)
	/// Base64 encryption/decryption is used for PlayerPrefs
	/// </summary>
	[DisallowMultipleComponent]
	public class DataManager : MonoBehaviour
	{
		private static readonly string prefix = "BugsBang-";

		/// <summary>
		/// This Gameobject defined as a Singleton.
		/// </summary>
		public static DataManager instance;

		void Awake ()
		{
			if (instance == null) {
				instance = this;
				DontDestroyOnLoad (gameObject);
			} else {
				Destroy (gameObject);
			}

		}

		void Start ()
		{
			//Load the status of the vibration
			Settings.vibrationEnabled = GetVibrationStatus ();
		}

		#region Load data

		/// <summary>
		/// Get the collected stars of the levels.
		/// </summary>
		/// <returns>The collected stars.</returns>
		/// <param name="levelsManager">Levels manager reference.</param>
		public static int GetCollectedStars (LevelsManager levelsManager)
		{
			int ID = 0;
			int cs = 0;
			for (int i = 0; i < levelsManager.levels.Count; i++) {
				ID = (i + 1);
				LevelsManager.Level.StarsNumber sn = GetLevelStars (ID);
				if (sn == LevelsManager.Level.StarsNumber.ONE) {
					cs += 1;
				} else if (sn == LevelsManager.Level.StarsNumber.TWO) {
					cs += 2;
				} else if (sn == LevelsManager.Level.StarsNumber.THREE) {
					cs += 3;
				}
			}
			return cs;
		}

		/// <summary>
		/// Get the number of stars of the given level
		/// </summary>
		/// <returns>The stars of level.</returns>
		/// <param name="ID">The ID of the Level.</param>
		public static LevelsManager.Level.StarsNumber GetLevelStars (int ID)
		{
			LevelsManager.Level.StarsNumber stars = LevelsManager.Level.StarsNumber.ZERO;
			string key = GetStarsStrKey (ID);
			if (PlayerPrefs.HasKey (key)) {
				stars = CommonUtil.IntNumberToLevelStarsNumberEnum (Base64.Decrypt (PlayerPrefs.GetString (key)));
			}
			return stars;
		}

		/// <summary>
		/// Determine if the level is locked or not.
		/// </summary>
		/// <returns><c>true</c> if the level is locked; otherwise, <c>false</c>.</returns>
		/// <param name="ID">The ID of the level.</param>
		public static bool IsLevelLocked (int ID)
		{
			bool isLocked = true;
			string key = GetLockedStrKey (ID);
			if (PlayerPrefs.HasKey (key)) {
				isLocked = CommonUtil.ZeroOneToTrueFalseBool (Base64.Decrypt (PlayerPrefs.GetString (key)));
			}
			return isLocked;
		}

		/// <summary>
		/// Get the score of the given level
		/// </summary>
		/// <returns>The score of level.</returns>
		/// <param name="ID">The ID of the Level.</param>
		public static int GetLevelScore (int ID)
		{
			int score = 0;
			string key = GetScoreStrKey (ID);
			if (PlayerPrefs.HasKey (key)) {
				score = CommonUtil.StringToInt (Base64.Decrypt (PlayerPrefs.GetString (key)));
			}
			return score;
		}

		/// <summary>
		/// Get the lives increment count
		/// </summary>
		/// <returns>The lives increment count.</returns>
		public static int GetLivesIncrementCount ()
		{
			int count = -1;
			string key = GetLivesIncrementCountStrKey ();
			if (PlayerPrefs.HasKey (key)) {
				count = CommonUtil.StringToInt (Base64.Decrypt (PlayerPrefs.GetString (key)));
			}
			return count;
		}

		/// <summary>
		/// Get the targets bang count
		/// </summary>
		/// <returns>The targets bang count.</returns>
		public static int GetTargetsBangCount ()
		{
			int count = -1;
			string key = GetTargetsBangCountStrKey ();
			if (PlayerPrefs.HasKey (key)) {
				count = CommonUtil.StringToInt (Base64.Decrypt (PlayerPrefs.GetString (key)));
			}
			return count;
		}

		/// <summary>
		/// Get the time pause count
		/// </summary>
		/// <returns>The time pause count.</returns>
		public static int GetTimePauseCount ()
		{
			int count = -1;
			string key = GetTimePauseCountStrKey ();
			if (PlayerPrefs.HasKey (key)) {
				count = CommonUtil.StringToInt (Base64.Decrypt (PlayerPrefs.GetString (key)));
			}
			return count;
		}

		/// <summary>
		/// Load the music mute value.
		/// </summary>
		/// <returns>The music mute value.</returns>
		public static bool GetMusicMuteValue ()
		{
			bool value = false;
			if (PlayerPrefs.HasKey (GetMusicMuteStrKey ())) {
				value = CommonUtil.ZeroOneToTrueFalseBool (Base64.Decrypt (PlayerPrefs.GetString (GetMusicMuteStrKey ())));
			}
			return value;
		}

		/// <summary>
		/// Load the sfx mute value.
		/// </summary>
		/// <returns>The sfx mute value.</returns>
		public static bool GetSFXMuteValue ()
		{
			bool value = false;
			if (PlayerPrefs.HasKey (GetSFXMuteStrKey ())) {
				value = CommonUtil.ZeroOneToTrueFalseBool (Base64.Decrypt (PlayerPrefs.GetString (GetSFXMuteStrKey ())));
			}
			return value;
		}

		/// <summary>
		/// Load the levels completed value.
		/// </summary>
		/// <returns>The levels completed value.</returns>
		public static bool GetLevelsCompletedValue ()
		{
			bool value = false;
			if (PlayerPrefs.HasKey (GetLevelsCompletedStrKey ())) {
				value = CommonUtil.ZeroOneToTrueFalseBool (Base64.Decrypt (PlayerPrefs.GetString (GetLevelsCompletedStrKey ())));
			}
			return value;
		}

		/// <summary>
		/// Load the vibration status.
		/// </summary>
		/// <returns>The vibration status.</returns>
		public static bool GetVibrationStatus ()
		{
			//By default vibration is on
			bool status = true;
			if (PlayerPrefs.HasKey (GetTimeVibrationStrKey ())) {
				status = CommonUtil.ZeroOneToTrueFalseBool (Base64.Decrypt (PlayerPrefs.GetString (GetTimeVibrationStrKey ())));
			}
			return status;
		}

		#endregion

		#region Save data

		/// <summary>
		/// Save the number of stars of the given level
		/// </summary>
		/// <param name="ID">The ID of the Level.</param>
		/// <param name="stars">The Stars of the Level.</param>
		public static void SaveLevelStars (int ID, LevelsManager.Level.StarsNumber stars)
		{
			PlayerPrefs.SetString (GetStarsStrKey (ID), Base64.Encrypt (CommonUtil.LevelStarsNumberEnumToIntNumber (stars).ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save level locked status.
		/// </summary>
		/// <param name="ID">The ID of the level.</param>
		/// <param name="isLocked">Whether the level is locked or not.</param>
		public static void SaveLevelLockedStatus (int ID, bool isLocked)
		{
			PlayerPrefs.SetString (GetLockedStrKey (ID), Base64.Encrypt (CommonUtil.TrueFalseBoolToZeroOne (isLocked).ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save level score.
		/// </summary>
		/// <param name="ID">The ID of the level.</param>
		/// <param name="score">The Score of the level.</param>
		public static void SaveLevelScore (int ID, int score)
		{
			PlayerPrefs.SetString (GetScoreStrKey (ID), Base64.Encrypt (score.ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save the lives increment count
		/// </summary>
		/// <param name="count">The lives increment count.</param>
		public static void SaveLivesIncrementCount (int count)
		{
			PlayerPrefs.SetString (GetLivesIncrementCountStrKey (), Base64.Encrypt (count.ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save the targets bang count
		/// </summary>
		/// <param name="count">The targets bang count.</param>
		public static void SaveTargetsBangCount (int count)
		{
			PlayerPrefs.SetString (GetTargetsBangCountStrKey (), Base64.Encrypt (count.ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save the time pause count
		/// </summary>
		/// <param name="count">The time pause count.</param>
		public static void SaveTimePauseCount (int count)
		{
			PlayerPrefs.SetString (GetTimePauseCountStrKey (), Base64.Encrypt (count.ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save the music mute value
		/// </summary>
		/// <param name="count">The music mute value.</param>
		public static void SaveMusicMuteValue (int value)
		{
			PlayerPrefs.SetString (GetMusicMuteStrKey (), Base64.Encrypt (value.ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save the sfx mute value
		/// </summary>
		/// <param name="count">The sfx mute value.</param>
		public static void SaveSFXMuteValue (int value)
		{
			PlayerPrefs.SetString (GetSFXMuteStrKey (), Base64.Encrypt (value.ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save the levels completed flag value
		/// </summary>
		/// <param name="count">The levels completed value.</param>
		public static void SaveLevelsCompletedValue (int value)
		{
			PlayerPrefs.SetString (GetLevelsCompletedStrKey (), Base64.Encrypt (value.ToString ()));
			PlayerPrefs.Save ();
		}

		/// <summary>
		/// Save the vibration status.
		/// </summary>
		/// <param name="status">The status of the vibration.</param>
		public static void SaveVibrationStatus (bool status)
		{
			PlayerPrefs.SetString (GetTimeVibrationStrKey (), Base64.Encrypt (CommonUtil.TrueFalseBoolToZeroOne (status).ToString ()));
			PlayerPrefs.Save ();
		}

		#endregion

		#region PlayerPrefs keys

		/// <summary>
		/// Return the locked string key of specific level.
		/// </summary>
		/// <returns>The locked string key.</returns>
		/// <param name="ID">The ID of the Level.</param>
		private static string GetLockedStrKey (int ID)
		{
			return Base64.Encrypt (prefix + "Level-" + ID + "-isLocked");
		}

		/// <summary>
		/// Return the stars string key of specific level.
		/// </summary>
		/// <returns>The stars string key.</returns>
		/// <param name="ID">The ID of the Level.</param>
		private static string GetStarsStrKey (int ID)
		{
			return  Base64.Encrypt (prefix + "Level-" + ID + "-Stars");
		}

		/// <summary>
		/// Return the score string key of specific level.
		/// </summary>
		/// <returns>The score string key.</returns>
		/// <param name="ID">The ID of the Level.</param>
		private static string GetScoreStrKey (int ID)
		{
			return  Base64.Encrypt (prefix + "Level-" + ID + "-Score");
		}

		/// <summary>
		/// Return the lives increment booster count string key.
		/// </summary>
		/// <returns>The lives increment count key.</returns>
		private static string GetLivesIncrementCountStrKey ()
		{
			return  Base64.Encrypt (prefix + "-LivesIncrementCount");
		}

		/// <summary>
		/// Return the targets bang booster count string key.
		/// </summary>
		/// <returns>The targets bang count key.</returns>
		private static string GetTargetsBangCountStrKey ()
		{
			return  Base64.Encrypt (prefix + "-TargetsBangCount");
		}

		/// <summary>
		/// Return the time pause booster count string key.
		/// </summary>
		/// <returns>The time pause count key.</returns>
		private static string GetTimePauseCountStrKey ()
		{
			return Base64.Encrypt (prefix + "-TimePauseCount");
		}

		/// <summary>
		/// Return the vibration string key.
		/// </summary>
		/// <returns>The vibration key.</returns>
		private static string GetTimeVibrationStrKey ()
		{
			return Base64.Encrypt (prefix + "-VibrationStatus");
		}

		/// <summary>
		/// Return the music mute string key.
		/// </summary>
		/// <returns>The music mute key.</returns>
		private static string GetMusicMuteStrKey ()
		{
			return Base64.Encrypt (prefix + "-MusicMute");
		}

		/// <summary>
		/// Return the sfx mute string key.
		/// </summary>
		/// <returns>The sfx mute key.</returns>
		private static string GetSFXMuteStrKey ()
		{
			return  Base64.Encrypt (prefix + "-SFXMute");
		}

		/// <summary>
		/// Return the levels completed string key.
		/// </summary>
		/// <returns>The levels completed key.</returns>
		private static string GetLevelsCompletedStrKey ()
		{
			return  Base64.Encrypt (prefix + "-LevelsCompleted");
		}


		#endregion

		/// <summary>
		/// Reset the game.
		/// </summary>
		public static void ResetGame ()
		{
			//Reset data of levels
			LevelsManager.instance.ResetLevels ();

			//Delete keys of boosters to reset them on load
			PlayerPrefs.DeleteKey (GetLivesIncrementCountStrKey ());
			PlayerPrefs.DeleteKey (GetTargetsBangCountStrKey ());
			PlayerPrefs.DeleteKey (GetTimePauseCountStrKey ());

			//Delete keys of audio sources
			PlayerPrefs.DeleteKey (GetSFXMuteStrKey ());
			PlayerPrefs.DeleteKey (GetMusicMuteStrKey ());

			Debug.Log ("Game data has been reset");
		}

		/// <summary>
		/// Determine if the given level is the last reached level or not.
		/// </summary>
		/// <param name="level">The Level reference.</param>
		public static void DetermineLastReachedLevel (LevelsManager.Level level)
		{
			if (level == null) {
				return;
			}

			if (!level.isLocked) {
				if (PlayerPrefs.HasKey (DataManager.GetLockedStrKey (level.ID + 1))) {
					if (DataManager.IsLevelLocked (level.ID + 1)) {
						//when the next level is locked , and current is not
						level.isLastRreached = true;
					} 
				} else if (!PlayerPrefs.HasKey (DataManager.GetStarsStrKey (level.ID))) {
					//when the level has not stars saved yet
					level.isLastRreached = true;
				}
			}
		}

	}
}